﻿using System;
using System.Collections.Generic;
using System.Linq;
using ButsaLib.Models;

namespace ButsaForecast.SpecialTypes
{
	/// <summary>
	/// Эксперименты.
	/// </summary>
	internal class DxPairCalculationB : IDxPairCalculation
	{
		private ForecastPair _forecastPair;

		public int ForecastPairId
		{
			get { return ForecastPair.ForecastPairId; }
		}

		public ForecastPair ForecastPair
		{
			get { return _forecastPair; }
			set
			{
				_forecastPair = value;
				//рассчет линии нападения
				HomeForwardAverageSkill = AttackLineSkill(_forecastPair.HomeTeamShot);
				GuestForwardAverageSkill = AttackLineSkill(_forecastPair.GuestTeamShot);
				HomeMiddlerAverageSkill = MiddleLineSkill(_forecastPair.HomeTeamShot);
				GuestMiddlerAverageSkill = MiddleLineSkill(_forecastPair.GuestTeamShot);
				HomeDefenderAverageSkill = DefenderLineSkill(_forecastPair.HomeTeamShot);
				GuestDefenderAverageSkill = DefenderLineSkill(_forecastPair.GuestTeamShot);
				HomeGoalKeeperSkill = GoalkeeperSkill(_forecastPair.HomeTeamShot);
				GuestGoalKeeperSkill = GoalkeeperSkill(_forecastPair.GuestTeamShot);
			}
		}

		public double HomeForwardAverageSkill { get; set; }

		public double HomeMiddlerAverageSkill { get; set; }

		public double HomeDefenderAverageSkill { get; set; }

		public double HomeGoalKeeperSkill { get; set; }

		public double GuestForwardAverageSkill { get; set; }

		public double GuestMiddlerAverageSkill { get; set; }

		public double GuestDefenderAverageSkill { get; set; }

		public double GuestGoalKeeperSkill { get; set; }

		public string HomeTeamName { get; set; }

		public string GuestTeamName { get; set; }

		public int HomeGoals { get; set; }

		public int GuestGoals { get; set; }

		public int HomeGoalsForecast { get; set; }

		public int GuestGoalsForecast { get; set; }

		/// <summary>
		/// Расчет силы атакующей линии.
		/// </summary>
		private double AttackLineSkill(TeamShot teamShot)
		{
			var forwardsList = teamShot.PlayerShots
				.Where(item => item.PrimaryPosition == "Cf" || item.PrimaryPosition == "Rf" ||
							   item.PrimaryPosition == "Lf" || item.PrimaryPosition == "Am" || item.SecondaryPosition == "Cf" ||
							   item.SecondaryPosition == "Rf" || item.SecondaryPosition == "Lf" || item.SecondaryPosition == "Am")
				.Where(item => !item.IsDiscvalificated && !item.IsTraumed)
				.ToList();

			List<double> skills = new List<double>();
			foreach (var playerShot in forwardsList)
			{
				double forwardSkill = (playerShot.TakingSkill * 0.85 +
									   playerShot.MarkingSkill * 0.85 +
									   playerShot.DribblingSkill +
									   playerShot.ReceptionSkill +
									   playerShot.StaminaSkill +
									   playerShot.PassSkill * 0.9 +
									   playerShot.StrikeValueSkill +
									   playerShot.StrikeAccuracySkill) *
									  playerShot.PhysicalFitness * 0.01 * (1 + (playerShot.Morality - 13) * 0.008);
				skills.Add(forwardSkill);
			}
			double averageLineSkill = AverrageForTop75Inc(skills.ToArray());

			//выясняем, сколько игрков выше averageLineSkill
			int count = skills.Count(item => item >= averageLineSkill);
			double correction = 1 + (count - 2)*0.05;

			return averageLineSkill * correction;
		}

		/// <summary>
		/// Расчет силы средней линии.
		/// </summary>
		private double MiddleLineSkill(TeamShot teamShot)
		{
			var attackMiddleList = teamShot.PlayerShots
				.Where(item => item.PrimaryPosition == "Lw" || item.PrimaryPosition == "Rw" || item.PrimaryPosition == "Am" ||
							   item.PrimaryPosition == "Lm" || item.PrimaryPosition == "Rm" || item.PrimaryPosition == "Cm" ||
							   item.SecondaryPosition == "Lw" || item.SecondaryPosition == "Rw" || item.SecondaryPosition == "Am" ||
							   item.SecondaryPosition == "Lm" || item.SecondaryPosition == "Rm" || item.SecondaryPosition == "Cm")
				.Where(item => !item.IsDiscvalificated && !item.IsTraumed)
				.ToList();
			var defenderMiddleList = teamShot.PlayerShots
				.Where(item => item.PrimaryPosition == "Lm" || item.PrimaryPosition == "Rm" || item.PrimaryPosition == "Cm" ||
							   item.PrimaryPosition == "Lwd" || item.PrimaryPosition == "Rwd" || item.PrimaryPosition == "Dm" ||
							   item.SecondaryPosition == "Lm" || item.SecondaryPosition == "Rm" || item.SecondaryPosition == "Cm" ||
							   item.SecondaryPosition == "Lwd" || item.SecondaryPosition == "Rwd" || item.SecondaryPosition == "Dm")
				.Where(item => !item.IsDiscvalificated && !item.IsTraumed)
				.ToList();

			List<double> skills = new List<double>();
			foreach (var playerShot in attackMiddleList)
			{
				double aMidleSkill = (playerShot.TakingSkill * 0.9 +
									  playerShot.MarkingSkill * 0.9 +
									  playerShot.DribblingSkill +
									  playerShot.ReceptionSkill +
									  playerShot.StaminaSkill +
									  playerShot.PassSkill +
									  playerShot.StrikeValueSkill * 0.9 +
									  playerShot.StrikeAccuracySkill * 0.9) *
									 playerShot.PhysicalFitness * 0.01 * (1 + (playerShot.Morality - 13) * 0.008);
				skills.Add(aMidleSkill);
			}
			foreach (var playerShot in defenderMiddleList)
			{
				double dMidleSkill = (playerShot.TakingSkill +
									  playerShot.MarkingSkill +
									  playerShot.DribblingSkill * 0.9 +
									  playerShot.ReceptionSkill +
									  playerShot.StaminaSkill +
									  playerShot.PassSkill +
									  playerShot.StrikeValueSkill * 0.85 +
									  playerShot.StrikeAccuracySkill * 0.85) *
									 playerShot.PhysicalFitness * 0.01 * (1 + (playerShot.Morality - 13) * 0.008);
				skills.Add(dMidleSkill);
			}
			double averageLineSkill = AverrageForTop75Inc(skills.ToArray());


			//выясняем, сколько игрков выше averageLineSkill
			int count = skills.Count(item => item >= averageLineSkill);
			double correction = 1 + (count - 2) * 0.05;

			return averageLineSkill * correction;
		}

		/// <summary>
		/// Расчет силы линии обороны.
		/// </summary>
		private double DefenderLineSkill(TeamShot teamShot)
		{
			var defendersList = teamShot.PlayerShots
				.Where(item => item.PrimaryPosition == "Lwd" || item.PrimaryPosition == "Rwd" || item.PrimaryPosition == "Dm" ||
							   item.PrimaryPosition == "Ld" || item.PrimaryPosition == "Rd" || item.PrimaryPosition == "Cd" ||
							   item.PrimaryPosition == "Sw" ||
							   item.SecondaryPosition == "Lwd" || item.SecondaryPosition == "Rwd" || item.SecondaryPosition == "Dm" ||
							   item.SecondaryPosition == "Ld" || item.SecondaryPosition == "Rd" || item.SecondaryPosition == "Cd" ||
							   item.SecondaryPosition == "Sw")
				.Where(item => !item.IsDiscvalificated && !item.IsTraumed)
				.ToList();

			List<double> skills = new List<double>();
			foreach (var playerShot in defendersList)
			{
				double aMidleSkill = (playerShot.TakingSkill +
									  playerShot.MarkingSkill +
									  playerShot.DribblingSkill +
									  playerShot.ReceptionSkill * 0.9 +
									  playerShot.StaminaSkill +
									  playerShot.PassSkill +
									  playerShot.StrikeValueSkill * 0.85 +
									  playerShot.StrikeAccuracySkill * 0.85) *
									 playerShot.PhysicalFitness * 0.01 * (1 + (playerShot.Morality - 13) * 0.008);
				skills.Add(aMidleSkill);
			}
			double averageLineSkill = AverrageForTop75Inc(skills.ToArray());

			//выясняем, сколько игрков выше averageLineSkill
			int count = skills.Count(item => item >= averageLineSkill);
			double correction = 1 + (count - 2) * 0.05;

			return averageLineSkill * correction;
		}

		/// <summary>
		/// Вычисление лучшего голкипера.
		/// </summary>
		private double GoalkeeperSkill(TeamShot teamShot)
		{
			var gkList = teamShot.PlayerShots
				.Where(item => item.PrimaryPosition == "Gk")
				.Where(item => !item.IsDiscvalificated && !item.IsTraumed)
				.ToList();

			double maxGk = gkList.Count != 0 ? gkList.Max(item => item.CalculatedTotalSkill) : 50;
			return maxGk;
		}

		/// <summary>
		/// Среднее для верхних 75%
		/// </summary>
		private double AverrageForTop75Inc(double[] values)
		{
			int startIndex = (int)(values.Length * 0.75) - 1;
			Array.Sort(values);
			double percentel = 0;
			for (int i = startIndex; i < values.Length; i++)
			{
				percentel += values[i];
			}
			percentel /= (values.Length - startIndex);
			return percentel;
		}

		public double GetTDV(double homeBonusCoefficient = 1)
		{
			double ht = (HomeForwardAverageSkill + HomeMiddlerAverageSkill + HomeDefenderAverageSkill +
			             HomeGoalKeeperSkill)*homeBonusCoefficient;
			double gt = (GuestForwardAverageSkill + GuestMiddlerAverageSkill +
			             GuestDefenderAverageSkill + GuestGoalKeeperSkill);

			double ratingCorrection = (_forecastPair.HomeTeamShot.Rating - _forecastPair.GuestTeamShot.Rating);
			if (ratingCorrection >= 10)
				ht *= 1.02;
			else if (ratingCorrection <= -10)
				gt *= 1.02;
			
			double tdv = ht - gt;
			return tdv;
		}

		public bool Recomendation
		{
			get { return true; }
		}
	}
}
